﻿global using Devonline.Core;
global using Devonline.Entity;
using System.Linq.Expressions;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Primitives;

namespace Devonline.AspNetCore;

/// <summary>
/// 公共数据处理服务
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
/// <typeparam name="TKey">键类型</typeparam>
public interface IServiceBase<TDbContext, TKey> where TDbContext : DbContext where TKey : IConvertible
{
    /// <summary>
    /// Gets or sets a flag indicating if changes should be persisted after CreateAsync, 
    /// UpdateAsync and DeleteAsync are called.
    /// True if changes should be automatically persisted, otherwise false.
    /// </summary>
    bool AutoSaveChanges { get; set; }
    #region 基础方法
    /// <summary>
    /// 从 httpContext 获取用户标识, 用户标识在 User.Claims 中的 type 为 sub; 在 request 中为 userId
    /// </summary>
    /// <returns></returns>
    string? GetUserId();
    /// <summary>
    /// 获取附件绝对地址
    /// </summary>
    /// <param name="fileName">附件文件名</param>
    /// <returns></returns>
    string GetAttachmentPath(string fileName);
    /// <summary>
    /// 获取 fileName 同扩展名临时文件名
    /// </summary>
    /// <param name="fileName"></param>
    /// <returns></returns>
    string GetTempFileName(string fileName, string? extension = null);
    /// <summary>
    /// 获取查询选项列表
    /// </summary>
    /// <returns>返回合并后的查询选项</returns>
    IEnumerable<KeyValuePair<string, StringValues>> GetRequestOptions();
    /// <summary>
    /// 从当前 request 中获取参数的值, 取值顺序 Query -> Form -> Header -> Cookie
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    T? GetRequestOption<T>(string key) where T : IConvertible;
    /// <summary>
    /// 获取上下文对象中参数/变量的值, 取值顺序 HttpContext -> Query -> Form -> Header -> Cookie
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    T? GetContextOption<T>(string key) where T : IConvertible;
    /// <summary>
    /// 调用实例的 Create 方法为基础字段赋值
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="entitySet"></param>
    void Create<TEntitySet>(TEntitySet entitySet);
    /// <summary>
    /// 调用实例的 Update 方法为基础字段赋值
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="entitySet"></param>
    void Update<TEntitySet>(TEntitySet entitySet);
    /// <summary>
    /// 提交当前操作
    /// </summary>
    /// <returns></returns>
    Task<int> SaveChangesAsync();
    #endregion

    #region 数据查询方法
    /// <summary>
    /// 非注入类型 TEntity 统一数据源查询入口, 可缓存数据源, 可返回泛型类型指定的任意类型引用
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <returns></returns>
    IQueryable<TEntitySet> GetQueryable<TEntitySet>() where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 非注入类型 TEntity 统一数据源查询入口, 可缓存数据源, 可返回泛型类型指定的任意类型引用
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="predicate">过滤条件</param>
    /// <returns></returns>
    IQueryable<TEntitySet> GetQueryable<TEntitySet>(Expression<Func<TEntitySet, bool>> predicate) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 根据 id 获取对象
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="id"></param>
    /// <returns></returns>
    Task<TEntitySet?> GetAsync<TEntitySet>(TKey id) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 从 QueryOptions 和上下文自动获取查询表达式的内容并执行查询返回分页的结果
    /// 暂不支持 orderby, select 和 expand 表达式
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <returns></returns>
    Task<PagedResult<TEntitySet>> GetPagedResultAsync<TEntitySet>() where TEntitySet : class, IEntitySet<TKey>;
    #endregion

    #region 数据操作方法
    /// <summary>
    /// 获取在更新复制属性值时需要忽略的字段配置
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <returns></returns>
    TypeAdapterConfig GetAdapterConfig<TEntitySet>() where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 新增或修改阶段判断满足条件的数据是否存在, 存在则抛出异常, 不存在则执行基类预定义赋值操作
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    Task UniqueAsync<TEntitySet>(TEntitySet entitySet) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 批量新增或修改数据对象模型到当前上下文, 但不提交
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="entitySets">业务数据</param>
    /// <returns></returns>
    Task AddOrUpdateAsync<TEntitySet>(params TEntitySet[] entitySets) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 单个数据对象的新增, 自动验证重复
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TEntitySet>(TEntitySet entitySet) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 单个数据对象的更新, 自动验证重复
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TEntitySet>(TEntitySet entitySet) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 删除记录
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <returns></returns>
    Task DeleteAsync<TEntitySet>(TKey id) where TEntitySet : class, IEntitySet<TKey>;
    #endregion
}

/// <summary>
/// 字符串作为主键的默认实现接口
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
public interface IServiceBase<TDbContext> : IServiceBase<TDbContext, string> where TDbContext : DbContext { }